package com.atguigu.exam.service.impl;


import com.atguigu.exam.entity.Category;
import com.atguigu.exam.entity.Question;
import com.atguigu.exam.exception.ExamException;
import com.atguigu.exam.mapper.CategoryMapper;
import com.atguigu.exam.mapper.QuestionMapper;
import com.atguigu.exam.service.CategoryService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Slf4j
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {
    @Autowired
    private QuestionMapper questionMapper;

    @Override
    public List<Category> getCategoriesWithCount() {
        //获取所有的分类列表，根据sort字段进行排序
        List<Category> categories = baseMapper.selectList(new LambdaQueryWrapper<Category>().orderByAsc(Category::getSort));
        //获取每个分类下的题目数量
        getQuestionCount(categories);
        return categories;
    }

    //获取每个分类下的题目数量
    private void getQuestionCount(List<Category> categories) {
        List<Map<String, Object>> countList = questionMapper.getCategoryCountList();
        //List<Map<String, Object>> 转换成 Map<Long,Long>
        Map<Long, Long> countMap = countList.stream().collect(Collectors.toMap(
                m -> Long.valueOf(m.get("category_id").toString()),// 设置key
                m -> Long.valueOf(m.get("count").toString()) // 设置value
        ));
//        System.out.println("countMap = " + countMap);
        categories.forEach(category -> {
            Long count = countMap.getOrDefault(category.getId(), 0L);
            category.setCount(count);
        });
    }

    @Override
    public List<Category> getCategoryTree() {
        //获取所有的分类列表，根据sort字段进行排序
        List<Category> categories = baseMapper.selectList(new LambdaQueryWrapper<Category>().orderByAsc(Category::getSort));
        //获取每个分类下的题目数量
        getQuestionCount(categories);
        //构建分类树结构
        List<Category> categoryTree = buildCategoryTree(categories);
        return categoryTree;
    }

    @Override
    public void saveCategory(Category category) {
        //根据父分类id和当前分类的名字查询父分类下是否有同名的分类 查是否存在的这个分类或者查个数
//        Category isExistCategory = baseMapper.selectOne(new LambdaQueryWrapper<Category>()
//                .eq(Category::getParentId, category.getParentId())
//                .eq(Category::getName, category.getName())
//        );
        Long count = baseMapper.selectCount(new LambdaQueryWrapper<Category>()
                .eq(Category::getParentId, category.getParentId())
                .eq(Category::getName, category.getName())
        );
        if (count > 0) {
            Category parentCategory = baseMapper.selectById(category.getParentId());
            throw new ExamException(511, "父级分类--" + parentCategory.getName() + "--下已存在同名的--" + category.getName() + "--分类,请重新输入分类名字");
        }
//        if (isExistCategory != null) {
//            Category parentCategory = baseMapper.selectById(category.getParentId());
//            throw new ExamException(511, "父级分类--" + parentCategory.getName() + "--下已存在同名的--" + isExistCategory.getName() + "--分类,请重新输入分类名字");
//        }
        baseMapper.insert(category);
    }

    @Override
    public void updateCategoryById(Category category) {
        //todo 同一父分类下！ 可以跟自己的name重复，不能跟其他的子分类name重复！
        //在同一父分类下id不同且名字相同的子分类不能存在
        //根据当前分类的父id查询所有的子分类 查询结果是一个属于当前父分类的子分类列表
        List<Category> categories = baseMapper.selectList(new LambdaQueryWrapper<Category>().
                eq(Category::getParentId, category.getParentId()));
        //获取所有分类的名字
        List<String> nameList = categories.stream().map(Category::getName).collect(Collectors.toList());
        //判断当前分类名字是否已存在
        if (nameList.contains(category.getName())) {
            //判断更新的名称是不是还是原来的名称
            Category oldCategory = baseMapper.selectOne(new LambdaQueryWrapper<Category>().eq(Category::getName, category.getName()));
            if (oldCategory.getId().equals(category.getId())) {
                //证明是自己，没有修改名称，可能是在更新其他字段，可以更新
                baseMapper.updateById(category);
            } else {
                //不是自己，但是在同一个父级分类下存在同名子分类，抛出异常
                Category parentCategory = baseMapper.selectById(category.getParentId());
                //可能更新顶级分类的name会出现null
                throw new ExamException(511, "父级分类--" + (ObjectUtils.isNotNull(parentCategory) ? parentCategory.getName() : "顶级分类") + "--下已存在同名的--" + category.getName() + "--分类,请重新更新分类名字");
            }
        }
        baseMapper.updateById(category);
    }

    @Override
    public void deleteCategoryById(Long id) {
        //当前分类下有子分类的不能删除或者有题目的不能删除
        Long childrenCount = baseMapper.selectCount(new LambdaQueryWrapper<Category>().eq(Category::getParentId, id));
        Long questionCount = questionMapper.selectCount(new LambdaQueryWrapper<Question>().eq(Question::getCategoryId, id));
        if (childrenCount > 0 || questionCount > 0) {
            throw new ExamException(513, "当前分类下有子分类或者有题目，不能删除");
        }
        baseMapper.deleteById(id);
    }

    private List<Category> buildCategoryTree(List<Category> categories) {
        Map<Long, List<Category>> parentIdMap = categories.stream()
                .collect(Collectors.groupingBy(Category::getParentId));
//        System.out.println("parentIdMap = " + parentIdMap);//在categories表中parent_id为13,14,15有子分类
        //遍历所有集合
        categories.forEach(category -> {
            //获取当前分类的id
            Long id = category.getId();
            //根据当前分类的id从map中获取子分类列表
            List<Category> childrenCategories = parentIdMap.getOrDefault(id, new ArrayList<>());
            //将子分类列表设置给当前分类对象中
            category.setChildren(childrenCategories);
            //todo 重新计算父分类下的题目数量 父分类的题目数量是当前分类下的题目数量加上所有子分类的题目数量之和
            //获取所有子分类的题目数量之和
            long childSumQuestionCount = childrenCategories.stream().mapToLong(c -> c.getCount() != null ? c.getCount() : 0L).sum();
            //获取当前分类的题目数量
            Long count = category.getCount();
            //设置当前分类的题目数量是当前分类下的题目数量加上所有子分类的题目数量之和
            category.setCount(count + childSumQuestionCount);
        });
        //最后只返回顶级分类 对categories进行过滤
        //获取顶级分类列表，父分类ID为0的 -- parent_id=0
        List<Category> categoryTree = categories.stream().filter(category -> category.getParentId() == 0).collect(Collectors.toList());
        return categoryTree;
    }
}